 COMMON SHARED /BatchTmp/ SavedBatchFile$,BatchFileLabel$(),BatchFileData$()
 COMMON SHARED /ConfigurationDL/ DLCount,DLName$(),DLRev$()
 COMMON SHARED /ConfigurationId/ SysName$,MfRev$
 COMMON SHARED /ConfigurationMe/ MeNRamSize,MeRDiskSize,MeDRamSize,MeDRamCount,MeFRomSize,MeFRomCount
 COMMON SHARED /ConstantsIO/ IOIdMin,IOIdMax,IOBaudMin,IOBaudMax,IOSBitsMin,IOSBitsMax
 COMMON SHARED /ConstantsMe/ MeNRamSizeMin,MeNRamSizeMax,MeRDiskSizeMin,MeRDiskSizeMax
 COMMON SHARED /ConstantsMisc/ ProgName$,SysAddr,EOFError
 COMMON SHARED /ConstantsRS232/ AnyString$,ResponseEnd$
 COMMON SHARED /DOS/ DOSDirFile$
 COMMON SHARED /LoadFile/ BytesSent
 COMMON SHARED /RS232Err/ SystErrCnt,SystErr$()
 COMMON SHARED /ReportErrTmp/ StaticErrReport
 COMMON SHARED /ReportTmp/ SeLogOpen
 COMMON SHARED /SelectedDF/ DFCount,DFFName$(),DFFSize(),DFDSize(),DFDJmpRev()
 COMMON SHARED /SelectedFiles/ SeDir$,SeLog$
 COMMON SHARED /SelectedIO/ SeIOType$,SeIOId,SeIOBaud,SeIOSBits,SeIOHand$
 COMMON SHARED /SelectedMe/ SeMeNRamSize,SeMeRDiskSize,SeMeDrivSize
 COMMON SHARED /SelectedPF/ PFFName$,PFFSize
 COMMON SHARED /SetErrorOccured/ ErrorOccured,LastError
 DECLARE FUNCTION GetBatch$(BatchFileName$,Label$)
 DECLARE FUNCTION GetBatchRep$(BatchFileName$,Label$,Idx)
 DECLARE FUNCTION ReadWord(BinaryFile,BlkStart,BlkIdx)
 DECLARE SUB CharVxi()
 DECLARE SUB CharVxiDL()
 DECLARE SUB CharVxiFiles()
 DECLARE SUB CharVxiMem()
 DECLARE SUB CkConfigVxiDrv()
 DECLARE SUB CkConfigVxiMem()
 DECLARE SUB CkViableVxi()
 DECLARE SUB CkVxiErr(Address,ErrMsg$,StopFlag)
 DECLARE SUB CleanUp()
 DECLARE SUB ConfigDisp()
 DECLARE SUB ConfigIO()
 DECLARE SUB ConfigVxi(BatchFileName$)
 DECLARE SUB ConfigVxiDrv()
 DECLARE SUB ConfigVxiMem()
 DECLARE SUB ConfigVxiProg()
 DECLARE SUB DumpVxiInput()
 DECLARE SUB ExecuteCmds(BatchFileName$,Label$)
 DECLARE SUB FinishReboot()
 DECLARE SUB GetBatchNum(BatchFileName$,Label$,Result,MinVal,MaxVal)
 DECLARE SUB GetBatchStr(BatchFileName$,Label$,Result$)
 DECLARE SUB GetBatchStrRep(BatchFileName$,Label$,Result$(),Count)
 DECLARE SUB GetDFInfo()
 DECLARE SUB GetPFInfo()
 DECLARE SUB GetValidIO(BatchFileName$)
 DECLARE SUB GetValidVxi(BatchFileName$)
 DECLARE SUB GetVxi2NumberCk(Address,Cmd$,Result1,Result2)
 DECLARE SUB GetVxiNumberCk(Address,Cmd$,Result)
 DECLARE SUB GetVxiPattern(Pattern$,Result$)
 DECLARE SUB GetVxiString(Address,Cmd$,Result$)
 DECLARE SUB GetVxiStringCk(Address,Cmd$,Result$)
 DECLARE SUB IOFailStop()
 DECLARE SUB IOTimeOutStop()
 DECLARE SUB LoadFile(FileName$,TotalBytes,FirstCall)
 DECLARE SUB PutBatchStrRep(StartNum,BatchFile,Label$,Result$(),Count)
 DECLARE SUB RebootVxi()
 DECLARE SUB Report(Msg$)
 DECLARE SUB ReportErr(ErrMsg$)
 DECLARE SUB ReportErrStop(ErrMsg$)
 DECLARE SUB ReportStatus(StatusMsg$)
 DECLARE SUB ReportStop(Msg$)
 DECLARE SUB SendVxi(Address,Cmd$)
 DECLARE SUB SendVxiCk(Address,Cmd$)
 DECLARE SUB SetIOSel(BatchFileName$)
 DECLARE SUB SetVxiSel(BatchFileName$)
 DECLARE SUB StopExecution()
 DECLARE SUB StoreIOSel(BatchFile)
 DECLARE SUB StoreVxiSel(BatchFile)
 DIM BatchFileLabel$(100),BatchFileData$(100)
 DIM DFFName$(20),DFFSize(20),DFDSize(20),DFDJmpRev(20)
 DIM DLName$(20),DLRev$(20)
 DIM SystErr$(20)
 ' HP's VXI Commander Auto-Configuration and Register Device Driver Loading.
 ' $Revision: 1.37 $ $Date: 92/08/05 13:01:57 $
 ' (c) Copyright 1991,1992, Hewlett-Packard Company, all rights reserved.
 '
 ' File/device usage.
 'I/O interface used for communication with the VXI mainframe is SeIOId
 ' aka. #1
 'ASCII files used for batch input of configuration is DefCfgFile$
 ' aka. #2
 'ROM program files used for input of program to be transfered are PFFName$
 ' aka. #3
 'Driver files used for input of driver to be transfered are DFFName()
 ' aka. #3
 'ASCII file used for logging progress is set with "EXECUTION LOG="
 ' aka. #4
 'ASCII file used for storing DIRectory listing is DOSDirFile$
 ' aka. #5
 '
 ' Setup constants.
 ProgName$="VXIDLD"		'Name of this program
 DefCfgFile$="VXIDLD.CFG"	'Name of Default user batch (Configuration) File, in current directory
 DOSDirFile$="VXIDLDTP"	'Name of file for temp. storage, in COM /DOS/
 SysAddr=0			'Address of SYSTEM or LOADER in VXI mainframe
 EOFError=62
 AnyString$=CHR$(128)
 ResponseEnd$=CHR$(13)+CHR$(10)
 'BatchLineLenMax=160
 'BatchLabelLenMax=17
 'BatchFileLenMax=100
 ' More constants.
 'SystErrCntMax=10		!Maximum number of errors in pseudo queue
 'FileNameLen=50		!Maximum number of characters in file names
 'PFFNameLen=FileNameLen	!Maximum length of ROM program file names
 'NameLen=7			!Maximum number of characters in instr. names
 'RevLen=7			!Maximum number of characters in driver revision
 'FCountMax=80		!Maximum number of files
 'CmdCountMax=80		!Maximum number of any type on command in .CFG
 'DFCountMax=20		!Maximum number of driver files
 'DFFNameLen=FileNameLen	!Maximum length of driver file names
 'DLCountMax=DFCountMax	!Maximum number of drivers loaded
 'DLNameLen=NameLen		!Maximum length of loaded driver names
 'DLRevLen=RevLen		!Maximum length of loaded driver revisions
 ' Valid ranges for selections.
 IOIdMin=1			'Minimum value of SeIOId
 IOIdMax=2			'Maximum value of SeIOId
 IOBaudMin=300		'Minimum value of SeIOBaud
 IOBaudMax=19200		'Maximum value of SeIOBaud
 IOSBitsMin=1		'Minimum value of SeIOSBits
 IOSBitsMax=2		'Maximum value of SeIOSBits
 MeNRamSizeMin=0.0		'Minimum value of SeMeNRamSize
 MeNRamSizeMax=2097152	'Maximum value of SeMeNRamSize (2 Mbyte now)
 MeRDiskSizeMin=0.0		'Minimum value of SeMeRDiskSize
 MeRDiskSizeMax=2097152	'Maximum value of SeMeRDiskSize (2 Mbyte now)
 '
 ' Setup static variables.
 SeLogOpen=0		'FALSE
 StaticErrReport=0		'FALSE
 ' Setup error flag.
 SystErrCnt=0		'Start with no errors in pseudo error queue
 SystErr$(10)="Too many errors"	'Always last err in queue !SystErrCntMax
 'FileNameLen, BatchFileLenMax, BatchLabelLenMax, + BatchLineLenMax-BatchLabelLenMax-1
 SavedBatchFile$=""		'none in use yet
 '
 ' Setup virtual global data structures.
 '  Configuration	Information on what is out there
 '   IO			Input/Output interfaces
 '   DLoaded			Drivers Loaded into mainframe
 '    Count				how many (0-DLCountMax)
 '    MID$(Name$(DLCountMax),DLNameLen)	driver Name
 '    MID$(Rev$(DLCountMax),DLRevLen)	driver Revision
 '   Mem			VXI Memory configuration
 '    NRamSize			Non-volatile RAM segment total size
 '    RDiskSize			RAM "disk" RAM segment total size
 '    DRamSize			Driver RAM segment total size
 '    DRamCount			how many Driver can be put in RAM
 '  MID$(SysName$,NameLen)	The Instrument name for the SYSTEM/LOADER
 '  MID$(MfRev$,RevLen)		Revision of Mainframe being downloaded to
 '  Selected			Information on what the user chooses to use
 '   MID$(Dir$,FileNameLen)		Directory file names are relative to
 '   MID$(Log$,FileNameLen)		File to which errors etc are reported
 '   IO				Input/Output interfaces
 '    Type$				what sort of I/O will we be using
 '    Id				which I/O interface to use (ADDRESS)
 '    Baud				baud rate for RS-232
 '    SBits				stop bits for RS-232
 '    Hand$				handshake for RS-232
 '   PFile			ROM Programs in Files
 '    MID$(ame$,PFFNameLen)		File Name
 '    FSize				total File Size (of all part combined)
 '   DFile			Drivers in Files
 '    Count				how many (0-DFCountMax)
 '    MID$(ame$(DFCountMax),DFFNameLen)	File Name
 '    FSize(DFCountMax)		File Size
 '    DSize(DFCountMax)		Driver Size
 '    DJmpRev(DFCountMax)		Driver's minimum Jump table Revision
 '   Mem			VXI Memory configuration
 '    NRamSize				Non-volatile RAM segment total size
 '    RDiskSize				RAM "disk" RAM segment total size
 '    DRamSize				Driver RAM segment total size
 '    DRamCount				how many Driver can be put in RAM
 '  DOSDirFile$		File for temporary storage of directory listing
 '
 ' Begin program.
 CALL ConfigDisp
 CALL Report("Beginning VXI ROM Program and Driver Download/Configuration Program")
 CALL GetValidIO(DefCfgFile$)	'Get Valid I/O interface and Disk selections
 CALL ConfigIO	'Configure I/O interface and Disk as per selections
 CALL ExecuteCmds(DefCfgFile$,"BEGINNING COMMAND")
 CALL CharVxi		'Characterize VXI system (and files for it)
 CALL GetValidVxi(DefCfgFile$)	'Get Valid VXI system (and files for it) selections
 CALL ConfigVxi(DefCfgFile$)	'Configure VXI system as per selections
 CALL Report("Configuration complete")
 CALL StopExecution
 END
 '
 SkipNextLine:	'Used as lowest common denominator way to handle errors
   RESUME NEXT
 '
 SetErrorOccured:	'Used as lowest common denominator way to handle errors
   ErrorOccured=1	'TRUE
   LastError=ERR
   RESUME NEXT
 '
 SUB ConfigDisp		'Configure Display for status messages
 'WARNING:  Loging to other than display not yet setup
   CLS
   VIEW PRINT 1 TO 24	'displays have >=25 lines, 25 is used for status
 END SUB 'ConfigDisp
 '
 SUB GetValidIO(BatchFileName$)	'Get I/O interface + Disk selections
   CALL ReportStatus("Reading directory and I/O device requests")
   CALL SetIOSel(BatchFileName$)
 END SUB 'GetValidIO
 '
 SUB SetIOSel(BatchFileName$)	'Setup I/O + Disk selections
 'WARNING:  Loging to other than display not yet setup
   'The default is the current directory so that it will run on non-HFS
   SeDir$=""	'Default driver file Directory (current directory)
   CALL GetBatchStr(BatchFileName$,"DIRECTORY",SeDir$)
   SeLog$=""	'Default output log destination is just the screen
   'Look for some permanent place to log errors, SeDir$ must already be set
   CALL GetBatchStr(BatchFileName$,"EXECUTION LOG",SeLog$)
   SeIOType$="RS-232"	'Set system default
   CALL GetBatchStr(BatchFileName$,"INTERFACE",SeIOType$)
 'RS-232 control begins
 'RS-232 control ends
   SELECT CASE SeIOType$
     CASE "HP-IB"
       CALL ReportErrStop("HP-IB interface not supported on DOS")
     CASE "RS-232"
       SeIOId=1
       SeIOBaud=9600
       CALL GetBatchNum(BatchFileName$,"BAUD",SeIOBaud,IOBaudMin,IOBaudMax)
       SeIOSBits=1
       CALL GetBatchNum(BatchFileName$,"STOP BITS",SeIOSBits,IOSBitsMin,IOSBitsMax)
       SeIOHand$="DTR"
       CALL GetBatchStr(BatchFileName$,"HANDSHAKE",SeIOHand$)
     CASE ELSE
       CALL ReportErrStop("Invalid INTERFACE setting '"+SeIOType$+"' read from '"+BatchFileName$+"'")
   END SELECT
   'Look for ADDRESS value in batch (configuration) file.
   CALL GetBatchNum(BatchFileName$,"ADDRESS",SeIOId,IOIdMin,IOIdMax)
 END SUB 'SetIOSel
 '
 SUB StoreIOSel(BatchFile)	'Store I/O + Disk selections
 'Dual of SetIOSel(BatchFileName$)
   ErrorOccured=0	'FALSE
   ON ERROR GOTO SetErrorOccured
   PRINT #BatchFile, "100 REM DIRECTORY="+SeDir$
   PRINT #BatchFile, "110 REM EXECUTION LOG="+SeLog$
   PRINT #BatchFile, "120 REM INTERFACE="+SeIOType$
   PRINT #BatchFile, "130 REM ADDRESS="+STR$(SeIOId)
   PRINT #BatchFile, "140 REM BAUD="+STR$(SeIOBaud)
   PRINT #BatchFile, "150 REM STOP BITS="+STR$(SeIOSBits)
   PRINT #BatchFile, "160 REM HANDSHAKE="+SeIOHand$
   ON ERROR GOTO 0
   IF 0<>ErrorOccured THEN CALL ReportErrStop("trouble writing to file")
 END SUB 'StoreIOSel
 '
 SUB ConfigIO		'Configure I/O interface and Disk as per selections
   CALL ReportStatus("Establishing connection to VXI mainframe via I/O device")
 'RS-232 control begins
     ErrorOccured=0	'FALSE
     ON ERROR GOTO SetErrorOccured
     IF SeIOBaud<>300 AND SeIOBaud<>1200 AND SeIOBaud<>2400 AND SeIOBaud<>4800 AND SeIOBaud<>7200 AND SeIOBaud<>9600 AND SeIOBaud<>19200  THEN 
        CALL ReportErrStop("Baud rate of "+STR$(SeIOBaud)+" not supported")
     END IF
     IF 19200=SeIOBaud THEN CALL ReportErrStop("Baud rate of "+STR$(SeIOBaud)+" not supported")
     IF "DTR"<>SeIOHand$ THEN CALL ReportErrStop("Only DTR hardware handshake supported")
     OPEN "COM"+LTRIM$(RTRIM$(STR$(SeIOId)))+": "+STR$(SeIOBaud)+",N,8,"+STR$(SeIOSBits) AS #1
     ON ERROR GOTO 0 
     IF 0<>ErrorOccured THEN CALL IOFailStop
 'RS-232 control ends
 'RS-232 control begins
     DIM Junk$
     CALL DumpVxiInput			'Dump any pending input
     ErrorOccured=0	'FALSE
     ON ERROR GOTO SetErrorOccured
     PRINT #1,CHR$(4);		'Get us to a known state
     CALL GetVxiPattern(AnyString$+"Select an instrument.",Junk$)
     PRINT #1,CHR$(3);		'Send clear to display system
     PRINT #1,"stwyse50"+CHR$(13);	'Force instrument labels
     PRINT #1,"stunknown"		'Get us to a known format
     CALL GetVxiPattern(AnyString$+": UNKNOWN"+ResponseEnd$,Junk$)
     IF 0<>INSTR(Junk$,"SYSTEM") THEN
       SysName$="SYSTEM"
     ELSE
       SysName$="LOADER"
     END IF
     PRINT #1,"si "+SysName$		'Get us to a known state in sys
     CALL GetVxiPattern("si "+SysName$+ResponseEnd$+SysName$+AnyString$+": busy"+ResponseEnd$,Junk$)
     'There may (not if busy) be a "...: "+ResponseEnd$ waiting now
     PRINT #1,CHR$(3);		'Send clear to SYSTEM/LOADER
     ON ERROR GOTO 0 
     IF 0<>ErrorOccured THEN CALL IOTimeOutStop
     CALL CkVxiErr(SysAddr,"While trying to connect to "+SysName$+" instrument",1)	'If errs then stop
     CALL GetVxiPattern(AnyString$+SysName$+AnyString$+": "+ResponseEnd$,Junk$)
     CALL DumpVxiInput			'Dump other "...:" if were 2
 'RS-232 control ends
   'Report errs and continue
   CALL CkVxiErr(SysAddr,"The preceding errors existed on the "+SysName$+" instrument when this program was started (may be normal)",0)
   CALL SendVxiCk(SysAddr,"*CLS")	'Flush the error queue
   CALL SendVxiCk(SysAddr,"*RST")
   CALL SendVxiCk(SysAddr,"DIAG:COMM:SER:STOR")	'It's working so save it
 END SUB 'ConfigIO
 '
 SUB CharVxi		'Characterize VXI system (and files for it)
   CALL ReportStatus("Characterizing current configuration of VXI mainframe")
   DIM Id$
   CALL GetVxiStringCk(SysAddr,"*IDN?",Id$)
   'Figure out what kind of system it is (SysName set before if using RS-232)
   Id$=MID$(Id$,INSTR(Id$,"KARD,")+5)	'Get Model string
   SysName$=MID$(Id$,1,INSTR(Id$,",0,")-1-(1)+1)	'Get Model string
   IF "LOADER"<>SysName$ THEN SysName$="SYSTEM"
   MfRev$=MID$(Id$,INSTR(Id$,",0,")+3)			'Get Revision string
   CALL CharVxiMem
   IF SysName$="SYSTEM" THEN CALL CharVxiDL    'SUB CharVxiDL cannot get Driver Names in FROM
 END SUB 'CharVxi
 '
 SUB CharVxiMem	'Characterize VXI system (and files for it)
 '
 '
 CALL GetVxi2NumberCk(SysAddr,"DIAG:DRAM:CRE?",MeDRamSize,MeDRamCount)'Total DRAM  size and # of Drivers Allocated
 CALL GetVxiNumberCk(SysAddr,"DIAG:NRAM:CRE?",MeNRamSize)              'Total NRAM  size Allocated
 CALL GetVxiNumberCk(SysAddr,"DIAG:RDISK:CRE?",MeRDiskSize)            'Total RDISK size Allocated
 '
 IF SysName$="LOADER" THEN
   CALL GetVxiNumberCk(SysAddr,"DIAG:FROM:SIZE?",MeFRomSize)  'Total FROM space not utilized by ROM Program.
   CALL GetVxiNumberCk(SysAddr,"DIAG:FROM:CRE?",MeFRomCount)  '# of Driver slots allocated.
 END IF
 END SUB 'CharVxiMem
 '
 SUB CharVxiDL
 '
 ' Get the list of drivers and versions that are loaded
 ' in the driver ram area.  The format of the returned string is:
 '    '<instrname>,<instrmodel>,<revision>,<where>[;<m>,<d>,<r>,<w>]...'
 '    or in the older (<A.04.00?) boxes
 '    '"<instrname>",+<versionnumber>[;"<aaa>,+<nnn>]...'
 '
   DIM DrvList$
   CALL GetVxiStringCk(SysAddr,"DIAG:DRIV:LIST?",DrvList$)
   IF 0=LEN(DrvList$) THEN GOTO BadDrvList
   OldFormat=0                         ' FALSE
   IF MID$(DrvList$,1,1-(1)+1)=CHR$(34) THEN OldFormat=1    ' TRUE when we see "
   DLCount=1
   IF ";"<>MID$(DrvList$,LEN(DrvList$)) THEN DrvList$=DrvList$+";"
   DO
     EndField=INSTR(DrvList$,",")		'find the end of 1st field
     IF OldFormat THEN
       IF MID$(DrvList$,2,2-(2)+1)=CHR$(34) THEN
         DLName$(DLCount)=""
       ELSE
         IF 4>EndField OR 10<EndField THEN GOTO BadDrvList	'DLNameLen
         'DLRevLen=RevLen	!Maximum length of loaded driver revisions
         DLName$(DLCount)=MID$(DrvList$,2,EndField-2-(2)+1)	'strip "s
       END IF
     ELSE  'New format
       IF 2>EndField OR 8<EndField THEN GOTO BadDrvList	'DLNameLen
       DLName$(DLCount)=MID$(DrvList$,1,EndField-1-(1)+1)	'this is driver name
       DrvList$=MID$(DrvList$,EndField+1)		'skip to start of 2nd field
       EndField=INSTR(DrvList$,",")		'find end of 2nd field
     END IF
     DrvList$=MID$(DrvList$,EndField+1)		'skip to start of next field
     IF OldFormat THEN
       EndField=INSTR(DrvList$,";")
     ELSE   'New format
       EndField=INSTR(DrvList$,",")
     END IF
     IF 2>EndField OR 8<EndField THEN GOTO BadDrvList	'DLRevLen
     DLRev$(DLCount)=MID$(DrvList$,1,EndField-1-(1)+1)
     DLCount=DLCount+1
     IF OldFormat THEN
       IF DLName$(DLCount-1)="" THEN DLCount=DLCount-1	'don't use "",+0
     ELSE  'New format
       IF LEN(DrvList$)<EndField+3 THEN GOTO BadDrvList
       IF MID$(DrvList$,EndField+1,EndField+3-(EndField+1)+1)<>"RAM" THEN DLCount=DLCount-1
     END IF
     EndField=INSTR(DrvList$,";")
     IF 0=EndField THEN GOTO BadDrvList
     DrvList$=MID$(DrvList$,EndField+1)	'skip to start of next record
   LOOP UNTIL UBOUND(DLName$,1)=DLCount OR 0=LEN(DrvList$)
   DLCount=DLCount-1
   '
   IF 0<>LEN(DrvList$) THEN
     DLCount=DLCount-1     'last one was one too many
     CALL ReportErr("Found more than "+STR$(DLCount)+" drivers loaded in VXI mainframe (this program can only use the first "+STR$(DLCount)+")")
   END IF
   EXIT SUB
   '
 BadDrvList:'
   DLCount=DLCount-1
   CALL ReportErr("List of loaded drivers was garbled after "+STR$(DLCount)+" drivers, not using '"+DrvList$+"'")
 END SUB 'CharVxiDL
'
'
 SUB GetValidVxi(BatchFileName$)	'Get Valid VXI system (and files for it) selections
   CALL ReportStatus("Reading configuration of VXI mainframe requests")
   CALL SetVxiSel(BatchFileName$)    '1.) Search directory for downloadable files + 2.) get user requests from CFG
   CALL CkViableVxi                  'Verify no conditions occured to stop program.
 END SUB 'GetValidVxi
 '
 SUB SetVxiSel(BatchFileName$)	'Setup VXI mainframe selections
   CALL CharVxiFiles                 'Set system defaults for files
   CALL GetBatchStr(BatchFileName$,"PROGRAM FILE",PFFName$)
   'Look for list of driver file names (if any found overwrite defaults)
   CALL GetBatchStrRep(BatchFileName$,"DRIVER FILE",DFFName$(),DFCount)
   IF 0<>DFCount THEN
     SeMeNRamSize=MeNRamSizeMin	'Set system default
     SeMeRDiskSize=MeRDiskSizeMin	'Set system default
   ELSE   'no change
     SeMeNRamSize=MeNRamSize	'Set system default
     SeMeRDiskSize=MeRDiskSize	'Set system default
   END IF
   'Look for NRAM and RDISK values in batch (configuration) file.
   'NRAM and RDISK requests are ignored in LOADER Mode (see SUB ConfigVxiMem)
   CALL GetBatchNum(BatchFileName$,"NRAM",SeMeNRamSize,MeNRamSizeMin,MeNRamSizeMax)
   CALL GetBatchNum(BatchFileName$,"RDISK",SeMeRDiskSize,MeRDiskSizeMin,MeRDiskSizeMax)
 END SUB 'SetVxiSel
 '
 SUB StoreVxiSel(BatchFile)	'Store VXI mainframe selections
 'Dual of SetVxiSel(BatchFileName$)
   ErrorOccured=0	'FALSE
   ON ERROR GOTO SetErrorOccured
   IF ""<>PFFName$ THEN PRINT #BatchFile, "210 REM PROGRAM FILE="+PFFName$
   PRINT #BatchFile, "220 REM NRAM="+STR$(SeMeNRamSize)
   PRINT #BatchFile, "230 REM RDISK="+STR$(SeMeRDiskSize)
   ON ERROR GOTO 0
   IF 0<>ErrorOccured THEN CALL ReportErrStop("trouble writing to file")
   CALL PutBatchStrRep(250,BatchFile,"DRIVER FILE",DFFName$(),DFCount)
 END SUB 'StoreVxiSel
 '
 SUB CkViableVxi	'Check specified VXI mainframe selections are possible
   NotViable=0	'FALSE until proven otherwise
   CALL GetDFInfo	'Fills in details + make sure files are in proper format
   SeMeDrivSize=0
   FOR I=1 TO DFCount
     SeMeDrivSize=SeMeDrivSize+DFDSize(I)   'Calculate total driver(s) size
   NEXT I
   '
   IF "SYSTEM"=SysName$ THEN    
     IF "A.06.00">MfRev$ THEN CALL ReportErr("Driver downloading is not supported on revisions before A.06.00, yours is revision "+MfRev$)
     IF SeMeRDiskSize<>MeRDiskSize AND MeRDiskSize<>0 THEN
       CALL ReportErr("Memory already allocated for RDISK.  Changing RDISK destroys contents.")
       CALL Report("Send 'DIAG:RDIS:CRE 0;:DIAG:BOOT' if contents not needed.")
       NotViable=1	'TRUE
     END IF
     IF SeMeNRamSize<>MeNRamSize AND (MeNRamSize<>0 OR MeRDiskSize<>0) AND 0=NotViable THEN
       CALL ReportErr("Memory already allocated for NRAM or RDISK.  Changing NRAM destroys contents.")
       CALL Report("Send 'DIAG:...:CRE 0;:DIAG:BOOT' if contents not needed.")
       NotViable=1	'TRUE
     END IF
     IF (SeMeDrivSize>MeDRamSize OR DFCount>MeDRamCount) AND (MeNRamSize<>0 OR MeRDiskSize<>0) AND 0=NotViable THEN
       CALL ReportErr("Memory already allocated for NRAM or RDISK.  Creating DRAM destroys contents.")
       CALL Report("Send 'DIAG:...:CRE 0;:DIAG:BOOT' if contents not needed.")
       NotViable=1	'TRUE
     END IF
     IF 0<>DLCount AND 0=NotViable THEN 'DLCount holds the # of drivers that reside on the VXI Mainframe in DRAM
       IF 0<>DFCount THEN
         CALL ReportErr("Driver(s) already loaded. Downloading new driver(s) destroys existing driver(s) in DRAM.")
         CALL Report("Send 'DIAG:DRAM:CRE 0;:DIAG:BOOT' if contents not needed.")
         NotViable=1	'TRUE
       ELSE
         CALL Report("You specified no new drivers to load, the "+STR$(DLCount)+" driver(s) already loaded will not be removed")
       END IF
     END IF
   ELSE	'"LOADER"=SysName$, RUN/LOAD switch in LOAD mode for 1406 command module.
     '
     IF DFCount>0 THEN    'test for drivers present.
       IF MeFRomCount>0 THEN  'Drivers already present.
          CALL ReportErr ("Driver(s) already exist or an area has been created for driver(s) in FROM.")
          CALL Report("Loading Driver(s) destroys existing driver(s).")
          CALL Report("Send 'DIAG:FROM:CRE 0' if contents not needed.")
          NotViable=1  'TRUE
       END IF
     END IF
     '
     CALL GetPFInfo	'Fills in details + makes sure file is in proper format
     IF ""<>PFFName$ THEN  'test for memory allocations that would be purged by ROM Program downloading
        IF (0<>MeDRamSize OR 0<>MeDRamCount OR 0<>MeNRamSize OR 0<>MeRDiskSize OR MeFRomCount<>0) THEN
          CALL ReportErr("Memory currently allocated for DRAM, NRAM, RDISK or FROM.")
          CALL Report("Loading ROM program destroys memory contents.")
          CALL Report("Send 'DIAG:....:CRE 0;:DIAG:BOOT' in RUN Mode for RDISK, NRAM or DRAM content removal.")
          CALL Report("Send 'DIAG:FROM:CRE 0' in LOAD Mode for FLASH ROM driver removal.")
          NotViable=1	'TRUE
        END IF
     END IF
     '
     IF DFCount=0 AND PFFName$="" THEN   'If nothing found for downloading
        CALL ReportStop("No Driver(s) or ROM Program found for downloading to FROM.")
     END IF
     '
   END IF
   IF NotViable THEN CALL ReportStop("You may also edit your CFG file command 'BEGINNING COMMAND=' to do this for you.")
 END SUB 'CkViableVxi
 '
 SUB ConfigVxi(BatchFileName$)	'Configure VXI system as per selections
   CALL ReportStatus("Configuring VXI mainframe as requested")
   CALL ConfigVxiProg
   CALL ConfigVxiMem
   CALL ExecuteCmds(BatchFileName$,"SETUP COMMAND")
   CALL CkConfigVxiMem
   CALL ConfigVxiDrv
   CALL ExecuteCmds(BatchFileName$,"CLEANUP COMMAND")
   CALL CkConfigVxiDrv
 END SUB 'ConfigVxi
 '
 SUB ConfigVxiProg	'Configure ROM program as per selection
   IF ""<>PFFName$ THEN
     IF "SYSTEM"=SysName$ THEN
       CALL ReportStop("Since the RUN/LOAD switch is set to RUN the ROM program file '"+SeDir$+PFFName$+"' will not be loaded")
     ELSE	'"LOADER"=SysName$
       DIM PartStr$	'temp variable to hold varying part of filename
       DIM PartName$	'PFFNameLen
       PartNum=1
       CALL LoadFile(SeDir$+PFFName$,PFFSize,1)
       WHILE BytesSent < PFFSize
         PartNum=PartNum+1
         IF PartNum>9 THEN CALL ReportErrStop("VXIDLD cannot support more than 9 ROM Program partitions")
         PartStr$=LTRIM$(RTRIM$(STR$(PartNum)))
         PartName$=SeDir$+MID$(PFFName$,1,LEN(PFFName$)-4-(1)+1)+PartStr$+MID$(PFFName$,LEN(PFFName$)-2)
         CALL LoadFile(PartName$,PFFSize,0)
       WEND
       CALL ReportStatus("")
       IF BytesSent<>PFFSize THEN
         CALL ReportErrStop("Sent "+STR$(BytesSent)+" bytes from "+SeDir$+PFFName$+", but it contains "+STR$(PFFSize)+" bytes")
       END IF
       CALL CkVxiErr(SysAddr,"While trying to load '"+SeDir$+PFFName$+"'-'"+PartName$+"' into instrument at address "+STR$(SysAddr),1) 'If errs then stop
       CALL Report("ROM Program download completed.")
       CALL Report("Move the RUN/LOAD switch to RUN position to verify proper RUN Mode operation.")
     END IF
   END IF
 END SUB 'ConfigVxiProg
 '
 SUB ConfigVxiMem	'Configure VXI system Memory as per selections
   IF "SYSTEM"=SysName$ THEN
     IF SeMeRDiskSize<>MeRDiskSize OR SeMeNRamSize<>MeNRamSize OR SeMeDrivSize>MeDRamSize OR DFCount>MeDRamCount THEN
       CALL ReportStatus("Configuring VXI mainframe's memory")
       CALL SendVxiCk(SysAddr,"DIAG:RDISK:CRE "+STR$(SeMeRDiskSize))
       IF SeMeNRamSize<>MeNRamSize OR SeMeDrivSize>MeDRamSize OR DFCount>MeDRamCount THEN
         CALL SendVxiCk(SysAddr,"DIAG:NRAM:CRE "+STR$(SeMeNRamSize))
         IF SeMeDrivSize>MeDRamSize OR DFCount>MeDRamCount THEN
           CALL SendVxiCk(SysAddr,"DIAG:DRAM:CRE "+STR$(SeMeDrivSize)+","+STR$(DFCount))
         END IF
       END IF
       CALL RebootVxi
     END IF   
   ELSE	'"LOADER"=SysName$
     IF DFCount>0 THEN   'If there are drivers to download
       IF ""<>PFFName$ THEN CALL CharVxiMem   'ROM Program was downloaded and we must gain new VXI status.
       '
       IF MeFRomSize=0 THEN
         CALL ReportErrStop("No Driver memory currently available in FLASH ROM.")
       END IF
       '
       CALL ReportStatus("Configuring VXI mainframe's FROM driver memory.")
       CALL SendVxiCk(SysAddr,"DIAG:FROM:CRE "+STR$(DFCount))
     END IF
   END IF
 END SUB 'ConfigVxiMem
 '
 SUB CkConfigVxiMem	'Check VXI system Memory is Configured correctly
   IF "SYSTEM"=SysName$ THEN
     CALL CharVxiMem			'Update state of mainframe
     ' Check that RAM was properly setup
     IF MeRDiskSize<>SeMeRDiskSize THEN CALL ReportErr(STR$(MeRDiskSize)+" bytes of RDISK reserved ("+STR$(SeMeRDiskSize)+" requested)")
     IF MeNRamSize<>SeMeNRamSize THEN CALL ReportErr(STR$(MeNRamSize)+" bytes of NRAM reserved ("+STR$(SeMeNRamSize)+" requested)")
     IF MeDRamSize<SeMeDrivSize THEN CALL ReportErrStop(STR$(MeDRamSize)+" bytes of DRAM reserved ("+STR$(SeMeDrivSize)+" requested) Program stopping.")
   ELSE   'LOADER
     IF DFCount>0 THEN  'We could only be downloading ROM so skip this check if #Drivers=0.
       CALL CharVxiMem			'Update state of mainframe if drivers exist.
       IF DFCount<>MeFRomCount THEN CALL ReportErrStop("Number of Drivers requested does not match Number of Drivers allocated. Program stopping.")
     END IF
   END IF
 END SUB 'CkConfigVxiMem
 '
 SUB ConfigVxiDrv	'Configure downloaded Drivers as per selections
   IF DFCount>0 THEN
     FOR I=1 TO DFCount
       CALL LoadFile(SeDir$+DFFName$(I),DFFSize(I),1)
       CALL ReportStatus("")
       IF BytesSent<>DFFSize(I) THEN
         CALL ReportErrStop("Sent "+STR$(BytesSent)+" bytes from "+SeDir$+DFFName$(I)+", but it contains "+STR$(DFFSize(I))+" bytes")
       END IF
       CALL CkVxiErr(SysAddr,"While trying to load '"+SeDir$+DFFName$(I)+"' into instrument at address "+STR$(SysAddr),1)	'If errs then stop
     NEXT I
     '
     IF "SYSTEM"=Sysname$ THEN
       CALL RebootVxi
     ELSE 'LOADER
       CALL SendVxiCk(SysAddr,"DIAG:DRIV:INST")
     END IF
     '
     CALL Report("Driver downloading completed.")
     '
   END IF
 END SUB 'ConfigVxiDrv
 '
 SUB CkConfigVxiDrv	'Check downloaded Drivers are Configured correctly
   IF "SYSTEM"=SysName$ THEN
     IF DFCount > 0 THEN  'Have Driver(s) downloaded
       CALL ReportStatus("Checking driver configuring in VXI mainframe")
       DIM Name$	'FileNameLen
       CALL CharVxiDL
       IF DFCount>DLCount THEN
         CALL ReportErr("Wrong number of drivers loaded (Expected "+STR$(DFCount)+", Found "+STR$(DLCount)+")")
       ELSE
         ' Check the actual loaded drivers to make sure it is the
         ' same as the one we have requested.
         ' I am assuming that driver names are the same as file names.
         FOR DFIdx=1 TO DFCount
           Name$=DFFName$(DFIdx)
           WHILE 0<>INSTR(Name$,"/")
             Name$=MID$(Name$,INSTR(Name$,"/")+1)
           WEND
           WHILE 0<>INSTR(Name$,"\")
             Name$=MID$(Name$,INSTR(Name$,"\")+1)
           WEND
           IF 0<>INSTR(Name$,".DC") THEN Name$=MID$(Name$,1,INSTR(Name$,".DC")-1-(1)+1)'Search for RS232 DOS type Drivers
           IF 0<>INSTR(Name$,"_DC") THEN Name$=MID$(Name$,1,INSTR(Name$,"_DC")-1-(1)+1)'Possible convention from Configuration file
           IF 0<>INSTR(Name$,"_DU") THEN Name$=MID$(Name$,1,INSTR(Name$,"_DU")-1-(1)+1)'Search for HPIB Drivers w/LIF Directory
           IF 0<>INSTR(Name$,".DU") THEN Name$=MID$(Name$,1,INSTR(Name$,".DU")-1-(1)+1)'Possible convention from Configuration file
           FoundMatch=0	'FALSE
           DLIdx=0
           DO
             DLIdx=DLIdx+1
             IF Name$=DLName$(DLIdx) THEN FoundMatch=1
           LOOP UNTIL DLCount=DLIdx OR FoundMatch
           IF 0<>FoundMatch THEN
             CALL Report("Driver '"+Name$+"' now appears in list of loaded drivers")
           ELSE
             CALL ReportErr("Driver '"+Name$+"' in file '"+DFFName$(DFIdx)+"' does not appear in the list of loaded drivers")
           END IF
         NEXT DFIdx
       END IF
     ELSE   'No Drivers found.
       CALL Report("No Driver found for downloading to DRAM.")
     END IF
   ELSE  'LOADER
     IF DFCount > 0 THEN  'Have Driver(s)
       CALL Report("Execute DIAG:DRIV:LIST? in RUN Mode to verify Driver(s) are downloaded to FLASH.")
     END IF
   END IF 
 END SUB 'CkConfigVxiDrv
 '
 SUB GetBatchNum(BatchFileName$,Label$,Result,MinVal,MaxVal)
   DIM TmpString$	'BatchLineLenMax
   TmpString$=GetBatch$(BatchFileName$,Label$)
   IF ""<>TmpString$ THEN
     CALL Report("Found "+BatchFileName$+" File Request: "+Label$+"="+TmpString$)
     ErrorOccured=0	'FALSE
     TmpVal=VAL(TmpString$)
     'If the string is not a valid number it's value will be 0
     IF ""=LTRIM$(RTRIM$(TmpString$)) THEN ErrorOccured=1
     IF 0<>ErrorOccured THEN
       CALL ReportErr(BatchFileName$+" contains a value for '"+Label$+"' which should be numeric, '"+TmpString$+"' will not be used")
     ELSE
       IF MinVal>TmpVal OR MaxVal<TmpVal THEN
         CALL ReportErr("'"+Label$+"' must be between "+STR$(MinVal)+" and "+STR$(MaxVal)+", '"+TmpString$+"' is not (using "+STR$(Result)+" instead)")
       ELSE
         IF TmpVal<>INT(TmpVal) THEN
           TmpVal=INT(TmpVal)
           CALL ReportErr("'"+Label$+"' must be an integer, '"+TmpString$+"' is not (using "+STR$(TmpVal)+" instead)")
         ELSE  'no errors observed
           Result=TmpVal
         END IF
       END IF
     END IF
   END IF
 END SUB 'GetBatchNum
 '
 SUB GetBatchStr(BatchFileName$,Label$,Result$)
   DIM TmpString$	'BatchLineLenMax
   TmpString$=GetBatch$(BatchFileName$,Label$)
   IF ""<>TmpString$ THEN
     CALL Report("Found "+BatchFileName$+" File Request: "+Label$+"="+TmpString$)
     Result$=TmpString$
   END IF
 END SUB 'GetBatchStr
 '
 SUB GetBatchStrRep(BatchFileName$,Label$,Result$(),Count)
   DIM TmpString$	'BatchLineLenMax
   CurIdx=0
   FoundCount=0		'Can't change Count unless we find one
   DO
     TmpString$=GetBatchRep$(BatchFileName$,Label$,CurIdx)
     IF ""<>TmpString$ THEN
       CALL Report("Found "+BatchFileName$+" File Request: "+Label$+"="+TmpString$)
       Result$(FoundCount+1)=TmpString$
         FoundCount=FoundCount+1
         Count=FoundCount
     END IF
   LOOP UNTIL ""=TmpString$ OR UBOUND(Result$,1)-1=FoundCount
   IF ""<>TmpString$ THEN
     Count=FoundCount-1
     CALL ReportErr("Found more than "+STR$(Count)+" values for '"+Label$+"' in '"+BatchFileName$+"' (this program can not use the later ones)")
   END IF
 END SUB 'GetBatchStrRep
 '
 SUB PutBatchStrRep(StartNum,BatchFile,Label$,Result$(),Count)
   ErrorOccured=0	'FALSE
   ON ERROR GOTO SetErrorOccured
   FOR Idx=1 TO Count
     PRINT #BatchFile, STR$(StartNum+Idx)+" REM "+Label$+"="+Result$(Idx)
   NEXT Idx
   ON ERROR GOTO 0
   IF 0<>ErrorOccured THEN CALL ReportErrStop("trouble writing to file")
 END SUB 'PutBatchStrRep
 '
 FUNCTION GetBatch$(BatchFileName$,Label$)	'Find Label$ in batch file, return value.
   GetBatch$=GetBatchRep$(BatchFileName$,Label$,0) : EXIT FUNCTION
 END FUNCTION 'GetBatch$
 '
 FUNCTION GetBatchRep$(BatchFileName$,Label$,Idx)
 ' Looks in batch (configuration) file for first occurrence of Label$,
 ' (starting at Idx significant lines from the start of the file)
 ' returns the value (the rest of the line) stored with it.
 ' Value of Label$ passed in must be all upper case.
   DIM LineBuf$	'BatchLineLenMax
   IF ""<>BatchFileName$ THEN
     IF SavedBatchFile$<>BatchFileName$ THEN
       ErrorOccured=0	'FALSE
       ON ERROR GOTO SetErrorOccured
       OPEN BatchFileName$ FOR INPUT AS #2
       ON ERROR GOTO 0
       IF 0=ErrorOccured THEN			'File opened okay
         CALL ReportStatus("Reading '"+BatchFileName$+"' file")
         SavedBatchFile$=BatchFileName$
         BatchIdx=0
         LineNum=0
         DO
           LineNum=LineNum+1
           ON ERROR GOTO SetErrorOccured
           LINE INPUT #2, LineBuf$
           ON ERROR GOTO 0
           LabelPos=INSTR(LineBuf$,"REM")
           IF LabelPos<>0 THEN LabelPos=LabelPos+3
           LineBuf$=LTRIM$(RTRIM$(MID$(LineBuf$,LabelPos+1)))
           IF 0=ErrorOccured AND 1<>INSTR(LineBuf$,"#") AND 0<>INSTR(LineBuf$,"=") THEN
             BatchFileLabel$(BatchIdx)=UCASE$(LTRIM$(RTRIM$(MID$(LineBuf$,1,INSTR(LineBuf$,"=")-1-(1)+1))))
             BatchFileData$(BatchIdx)=LTRIM$(RTRIM$(MID$(LineBuf$,INSTR(LineBuf$,"=")+1)))
             BatchIdx=BatchIdx+1
           END IF
         LOOP UNTIL ErrorOccured OR UBOUND(BatchFileLabel$,1)-1=BatchIdx	'EOF OR out of room
         CLOSE #2
         BatchFileLabel$(BatchIdx)=""
         BatchFileData$(BatchIdx)=""
         IF ErrorOccured THEN
           IF LastError<>EOFError THEN CALL ReportErrStop("BASIC error "+STR$(LastError)+" while reading '"+BatchFileName$+"' file, line "+STR$(LineNum))
           'ELSE error was due to EOF
         ELSE				'Found desired label
           BatchIdx=BatchIdx-1
           CALL ReportErr("Found more than "+STR$(BatchIdx)+" significant lines in '"+BatchFileName$+"' (this program can not use the later ones)")
           CALL Report("Last line used is:  REM "+BatchFileLabel$(BatchIdx)+"="+BatchFileData$(BatchIdx))
         END IF	'Label not found in file
       ELSE		'File did not open
         CALL ReportErr("Unable to open file '"+BatchFileName$+"' (file will not be used)")
         BatchFileName$=""	'Clear file name so we won't try to use it again
       END IF
     END IF
     Idx=Idx-1
     DO
       Idx=Idx+1
     LOOP UNTIL BatchFileLabel$(Idx)=Label$ OR BatchFileLabel$(Idx)=""
     Idx=Idx+1
     GetBatchRep$=BatchFileData$(Idx-1) : EXIT FUNCTION
   END IF		'Empty file name (probably previously detected as bad)
   GetBatchRep$="" : EXIT FUNCTION
 END FUNCTION 'GetBatchRep$
 '
 SUB IOTimeOutStop
   CALL ReportErrStop("Timeout while attempting to access VXI mainframe")
 END SUB 'IOTimeOutStop
 '
 SUB IOFailStop
   CALL ReportErr("Unable to communicate with the VXI mainframe via the "+SeIOType$+" connection at address "+STR$(SeIOId))
   CALL Report("Check that the proper cable is connected from the port at that address to the VXI mainframe")
 'RS-232 control begins
     CALL Report("Response to 'SYST:COMM:SER:BAUD?' should be "+STR$(SeIOBaud))
     CALL Report("Response to 'SYST:COMM:SER:BITS?' should be 8")
     CALL Report("Response to 'SYST:COMM:SER:PAR?' should be NONE")
     CALL Report("Response to 'SYST:COMM:SER:SBIT?' should be "+STR$(SeIOSBits))
     SELECT CASE SeIOHand$
       CASE "XON"
         CALL Report("Response to 'SYST:COMM:SER:PACE?' should be XON")
         CALL Report("Response to 'SYST:COMM:SER:CONT:DTR?' should be ON")
         CALL Report("Response to 'SYST:COMM:SER:CONT:RTS?' should be ON")
       CASE "DTR"
         CALL Report("Response to 'SYST:COMM:SER:PACE?' should be NONE")
         CALL Report("Response to 'SYST:COMM:SER:CONT:DTR?' should be IBF")
         CALL Report("Response to 'SYST:COMM:SER:CONT:RTS?' should be ON")
       CASE "RTS"
         CALL Report("Response to 'SYST:COMM:SER:PACE?' should be NONE")
         CALL Report("Response to 'SYST:COMM:SER:CONT:DTR?' should be ON")
         CALL Report("Response to 'SYST:COMM:SER:CONT:RTS?' should be IBF")
     END SELECT
     CALL Report("If you need to change any of these settings you will also want to execute 'DIAG:COMM:SER:STOR'")
     CALL ReportStop("You may want to try using a communications program (terminal emulator) setup as shown to check out the communications path")
 'RS-232 control ends
 END SUB 'IOFailStop
 '
 SUB ReportErrStop(ErrMsg$)
   CALL ReportErr(ErrMsg$)
   CALL ReportStatus("Program stopping because of error")
   CALL StopExecution
 END SUB 'ReportErrStop
 '
 SUB ReportErr(ErrMsg$)
   StaticErrReport=1		'TRUE
   BEEP
   CALL Report("ERROR:  "+ErrMsg$)
 END SUB 'ReportErr
 '
 SUB ReportStop(Msg$)
   CALL Report(Msg$)
   CALL ReportStatus("Program stopping because of error")
   CALL StopExecution
 END SUB 'ReportStop
 '
 SUB Report(Msg$)
   DIM FileName$	'FileNameLen
   DIM NextLine$
   WHILE 0<>INSTR(Msg$,ResponseEnd$)
     MID$(Msg$,INSTR(Msg$,ResponseEnd$),LEN(ResponseEnd$))=" "+CHR$(13)
   WEND
   IF ""<>SeLog$ AND 0=SeLogOpen THEN	'Open up log if needed
     ErrorOccured=0	'FALSE
     ON ERROR GOTO SetErrorOccured
     OPEN SeDir$+SeLog$ FOR OUTPUT AS #4
     ON ERROR GOTO 0
     IF 0<>ErrorOccured THEN	'File did not open
       FileName$=SeLog$
       SeLog$=""	'Clear file name so we won't try to use it again
       CALL ReportErr("Unable to open log file '"+SeDir$+FileName$+"' (file will not be used)")
     ELSE
       SeLogOpen=1	'TRUE
     END IF
   END IF
   DO
     IF 80>=LEN(Msg$) THEN
       NextLine$=Msg$
       Msg$=""
     ELSE
       PosBreak=INSTR(Msg$," "+CHR$(13))
       IF 1<PosBreak AND 80>PosBreak THEN
         NextLine$=MID$(Msg$,1,PosBreak-1-(1)+1)
         Msg$="  "+MID$(Msg$,PosBreak+LEN(ResponseEnd$))
       ELSE
         PosNextBreak=1
         DO
           PosBreak=PosNextBreak
           PosNextBreak=PosNextBreak+INSTR(MID$(Msg$,PosBreak+1)," ")
         LOOP UNTIL PosBreak=PosNextBreak OR 80<PosNextBreak
         IF LEN("  ")>=PosBreak THEN PosBreak=80
         NextLine$=MID$(Msg$,1,PosBreak-1-(1)+1)
         Msg$="  "+MID$(Msg$,PosBreak+1)
       END IF
     END IF
     PRINT NextLine$
     IF ""<>SeLog$ THEN
       ErrorOccured=0	'FALSE
       ON ERROR GOTO SetErrorOccured
       PRINT #4, NextLine$
       ON ERROR GOTO 0
       IF 0<>ErrorOccured THEN
         FileName$=SeLog$
         SeLog$=""	'Clear file name so we won't try to use it again
         CALL ReportErr("Unable to write to log file '"+SeDir$+FileName$+"' (file will not be used)")
       END IF
     END IF
   LOOP UNTIL ""=Msg$
 END SUB 'Report
 '
 SUB ReportStatus(StatusMsg$)
   IF ""<>StatusMsg$ THEN
     CurrentRow=CSRLIN : CurrentCol=POS(0) : VIEW PRINT 25 TO 25 : CLS : PRINT ProgName$+":  "+StatusMsg$; : VIEW PRINT 1 TO 24 : LOCATE CurrentRow,CurrentCol
   ELSE				'Clearing status
     CurrentRow=CSRLIN : CurrentCol=POS(0) : VIEW PRINT 25 TO 25 : CLS : PRINT; : VIEW PRINT 1 TO 24 : LOCATE CurrentRow,CurrentCol
   END IF
 END SUB 'ReportStatus
 '
 SUB StopExecution
   CALL ReportStatus("Program stopping")
   CALL CleanUp
   CALL ReportStatus("")
   SYSTEM
 END SUB 'StopExecution
 '
 SUB RebootVxi
   CALL ReportStatus("Re-booting VXI mainframe")
   CALL SendVxi(SysAddr,"DIAG:BOOT")
   SLEEP 2				'Make sure re-boot has a chance to start
 'RS-232 control begins
     CALL DumpVxiInput   'clear out buffer
     CALL FinishReboot
 'RS-232 control ends
 END SUB 'RebootVxi
 '
 SUB FinishReboot
 'RS-232 control begins
     DIM Junk$
     ErrorOccured=0	'FALSE
     ON ERROR GOTO SetErrorOccured
     PRINT #1,CHR$(4)+"st unknown"		'Just in case
     ON ERROR GOTO 0 
     IF 0<>ErrorOccured THEN CALL IOTimeOutStop
     CALL GetVxiPattern(AnyString$+": UNKNOWN"+ResponseEnd$,Junk$)
     CALL CkVxiErr(SysAddr,"The preceding error(s) were caused by the boot (may be normal)",0)	'Report errs and continue
     CALL SendVxiCk(SysAddr,"*CLS")	'Flush the error queue
     CALL SendVxiCk(SysAddr,"*RST")
 'RS-232 control ends
 END SUB 'FinishReboot
 '
 SUB SendVxiCk(Address,Cmd$)
 ' This sends a command (no results expected) to the VXI mainframe,
 ' then checks to see if an error resulted and if so halts execution
   CALL SendVxi(Address,Cmd$)
   CALL CkVxiErr(Address,"While sending command '"+Cmd$+"' to "+STR$(Address),1)	'If errs then stop
 END SUB 'SendVxiCk
 '
 SUB SendVxi(Address,Cmd$)
 ' This sends a command (no results expected) to the VXI mainframe.
 'RS-232 control begins
     DIM Junk$
     ErrorOccured=0	'FALSE
     ON ERROR GOTO SetErrorOccured
     IF Address=SysAddr THEN
       PRINT #1,CHR$(4)+"si ";SysName$ 'may not be LADD 0 in E1405
       CALL GetVxiPattern(AnyString$+"Select an instrument."+AnyString$+SysName$+"_"+AnyString$+": "+ResponseEnd$,Junk$)
     ELSE
       PRINT #1,CHR$(4)+"sa ";Address
       CALL GetVxiPattern(AnyString$+"Select an instrument."+AnyString$+"_"+LTRIM$(RTRIM$(STR$(Address)))+": "+ResponseEnd$,Junk$)
     END IF
     PRINT #1,Cmd$
     ON ERROR GOTO 0 
     IF 0<>ErrorOccured THEN CALL IOTimeOutStop
     IF INSTR(Cmd$,"DIAG:BOOT") THEN
         CALL DumpVxiInput  'clear out buffer
     ELSE
       SELECT CASE Cmd$
         CASE CHR$(3)		'Clear command isn't echoed as such
           CALL GetVxiPattern(AnyString$+": "+ResponseEnd$,Junk$)
         CASE "*CLS"
           SystErrCnt=0	'Clear out pseudo error queue
           CALL GetVxiPattern(Cmd$+ResponseEnd$,Junk$)
         CASE ELSE
           CALL GetVxiPattern(Cmd$+ResponseEnd$,Junk$)
       END SELECT
     END IF
 'RS-232 control ends
 END SUB 'SendVxi
 '
 SUB CkVxiErr(Address,ErrMsg$,StopFlag)
 ' This checks if there are errors on an instrument and if so reports them.
   DIM ErrResponse$
   FoundError=0		'FALSE
   DO
 'RS-232 control begins
       IF 0<SystErrCnt THEN
         ErrResponse$=SystErr$(1)
         FOR ErrIdx=2 TO SystErrCnt
           SystErr$(ErrIdx-1)=SystErr$(ErrIdx)
         NEXT ErrIdx
         SystErrCnt=SystErrCnt-1
         IF 0=FoundError THEN
           CALL Report("Note that the following errors may have been caused by the previous command, errors are not detected immediately via RS-232")
         END IF
       ELSE
         ErrResponse$="+0,"+CHR$(34)+"No error"+CHR$(34)
       END IF
 'RS-232 control ends
     IF "+0,"+CHR$(34)+"No error"+CHR$(34)<>ErrResponse$ THEN
       CALL ReportErr("Encountered error '"+ErrResponse$+"' on instrument at address "+STR$(Address))
       FoundError=1		'TRUE
     END IF
   LOOP UNTIL "+0,"+CHR$(34)+"No error"+CHR$(34)=ErrResponse$
   IF FoundError THEN
     IF StopFlag THEN
       CALL ReportStop(ErrMsg$)
     ELSE
       CALL Report(ErrMsg$)
     END IF
   END IF
 END SUB 'CkVxiErr
 '
 SUB DumpVxiInput
 ' Should only be used for serial I/O.
 ' Reads from input stream until timeout.  Does not save any errors it sees.
 'RS-232 control begins
     DO
       Char$=""
       StartTime=TIMER
       IF 86340-1-1<StartTime THEN
         SLEEP 1
         StartTime=-1
       END IF
       DO	'Wait up to 1 sec if errors or no input available
         ON ERROR GOTO SkipNextLine	'Handle I/O error with re-tries
         IF NOT EOF(1) THEN Char$=INPUT$(1,#1)
         ON ERROR GOTO 0
       LOOP UNTIL ""<>Char$ OR 1<TIMER-StartTime
     LOOP UNTIL ""=Char$
 DumpFinished:'
 'RS-232 control ends
 END SUB 'DumpVxiInput
 '
 SUB GetVxiPattern(Pattern$,Result$)
 ' Should only be used for serial I/O.
 ' Should not be called with an empty pattern.
 ' Checks that the input stream matches the given pattern.
 ' Note this does not shift window 1 character at a time, so looking for
 '   xABAC will match xABAC or xABCABAC, but not xABABAC
 'RS-232 control begins
     'pattern may contain "Any String" characters
     'if pattern ends in "Any String" then a timeout is not an error
     AnyMatch=0
     ExactMatch=1
     Result$=""
     DO
       IF AnyString$=MID$(Pattern$,ExactMatch,ExactMatch-(ExactMatch)+1) THEN
         AnyMatch=ExactMatch
         IF LEN(Pattern$)>ExactMatch THEN ExactMatch=ExactMatch+1
       END IF
       Char$=""
       StartTime=TIMER
       IF 86340-1-20<StartTime THEN
         SLEEP 20
         StartTime=-20
       END IF
       DO	'Wait up to 20 sec if errors or no input available
         ON ERROR GOTO SkipNextLine	'Handle I/O error with re-tries
         IF NOT EOF(1) THEN Char$=INPUT$(1,#1)
         ON ERROR GOTO 0
       LOOP UNTIL ""<>Char$ OR 20<TIMER-StartTime
       IF ""=Char$ THEN GOTO NoMoreInput
       IF CHR$(7)=Char$ THEN
         SystErrCnt=SystErrCnt+1
         IF 10>SystErrCnt THEN	'SystErrCntMax
           DIM ErrMsg$
           ThisErr=SystErrCnt	'Following CALL will change SystErrCnt
           CALL GetVxiPattern(AnyString$+ResponseEnd$,ErrMsg$)
           IF 0<>INSTR(ErrMsg$,ResponseEnd$) THEN
             SystErr$(ThisErr)=MID$(ErrMsg$,1,LEN(ErrMsg$)-LEN(ResponseEnd$)-(1)+1)
           ELSE
             SystErr$(ThisErr)=MID$(ErrMsg$,1,80-25-(1)+1)+" (end of message missing)"
           END IF
         ELSE
           SystErrCnt=10		'SystErrCntMax, stop at end of queue
         END IF
       END IF
       ErrorOccured=0	'FALSE
       ON ERROR GOTO SetErrorOccured
       Result$=Result$+Char$
       ON ERROR GOTO 0 
       'Just give back what will fit
       IF 0<>ErrorOccured THEN Result$=MID$(Result$,2)+Char$
       IF MID$(Pattern$,ExactMatch,ExactMatch-(ExactMatch)+1)=Char$ THEN
         ExactMatch=ExactMatch+1
       ELSE
         IF 0=AnyMatch THEN GOTO MatchFailed
         'ELSE go back to last AnyString$
         IF ExactMatch<>AnyMatch THEN	'IF not at end of pattern
           ExactMatch=AnyMatch+1
           IF MID$(Pattern$,ExactMatch,ExactMatch-(ExactMatch)+1)=Char$ THEN
             ExactMatch=ExactMatch+1
           END IF
         END IF
       END IF
     LOOP UNTIL ExactMatch>LEN(Pattern$)
     GOTO ExitSub	'Found the pattern we were looking for
 NoMoreInput:'
     IF ExactMatch<LEN(Pattern$) OR AnyString$<>MID$(Pattern$,LEN(Pattern$)) THEN
 MatchFailed:'
       IF AnyString$+"Select an instrument."<>Pattern$ OR 0=INSTR(Result$,"IBASIC Booting") THEN	'In case DIAG:IBAS:CurrentRow=CSRLIN : CurrentCol=POS(0) : VIEW PRINT 25 TO 25 : CLS : PRINT BUIL; : VIEW PRINT 1 TO 24 : LOCATE CurrentRow,CurrentCol
         DIM HumanPattern$
         WHILE ""<>Pattern$
           IF AnyString$=MID$(Pattern$,1,1-(1)+1) THEN
             HumanPattern$=HumanPattern$+"..."
           ELSE
             HumanPattern$=HumanPattern$+MID$(Pattern$,1,1-(1)+1)
           END IF
           Pattern$=MID$(Pattern$,2)
         WEND
         IF ""=Result$ THEN
           CALL IOFailStop
         ELSE
           CALL ReportErr("Failed to find '"+HumanPattern$+"' in serial input, found '"+Result$+"'")
           CALL Report("other program may be interfering or format/baud rate may be wrong")
         END IF
       END IF
     END IF
 'RS-232 control ends
 ExitSub:'
 END SUB 'GetVxiPattern
 '
 SUB GetVxiStringCk(Address,Cmd$,Result$)
   CALL GetVxiString(Address,Cmd$,Result$)
   CALL CkVxiErr(Address,"While sending query '"+Cmd$+"' to "+STR$(Address),1)	'If errs then stop
   IF ""=LTRIM$(RTRIM$(Result$)) THEN
     CALL ReportErr("Expected a non-blank string, but received '"+Result$+"' while sending query '"+Cmd$+"' to "+STR$(Address))
   END IF
 END SUB 'GetVxiStringCk
 '
 SUB GetVxiString(Address,Cmd$,Result$)
   CALL SendVxi(Address,Cmd$)
 'RS-232 control begins
     CALL GetVxiPattern(AnyString$+ResponseEnd$,Result$)
     IF LEN(Result$)>LEN(ResponseEnd$) THEN
       Result$=MID$(Result$,1,LEN(Result$)-LEN(ResponseEnd$)-(1)+1)
     ELSE
       CALL ReportErr("Expected a longer string, received '"+Result$+"' while sending query '"+Cmd$+"' to "+STR$(Address))
     END IF
 'RS-232 control ends
 END SUB 'GetVxiString
 '
 SUB GetVxiNumberCk(Address,Cmd$,Result)
   CALL SendVxi(Address,Cmd$)
   ErrorOccured=0	'FALSE
 'RS-232 control begins
     DIM Result$
     CALL GetVxiPattern(AnyString$+ResponseEnd$,Result$)
     Result=VAL(Result$)
     'If the string is not a valid number it's value will be 0
     IF ""=LTRIM$(RTRIM$(Result$)) THEN ErrorOccured=1
 'RS-232 control ends
   CALL CkVxiErr(Address,"While sending query '"+Cmd$+"' to "+STR$(Address),1)	'If errs then stop
   IF 0<>ErrorOccured THEN
     CALL ReportErr("Expected a number, but received '"+Result$+"' while sending query '"+Cmd$+"' to "+STR$(Address)+" (using 0)")
     Result=0
   END IF
 END SUB 'GetVxiNumberCk
 '
 SUB GetVxi2NumberCk(Address,Cmd$,Result1,Result2)
   CALL SendVxi(Address,Cmd$)
   ErrorOccured=0	'FALSE
 'RS-232 control begins
     DIM Result$
     CALL GetVxiPattern(AnyString$+ResponseEnd$,Result$)
     Result1=VAL(Result$)
     'If the string is not a valid number it's value will be 0
     IF ""=LTRIM$(RTRIM$(Result$)) THEN ErrorOccured=1
     ON ERROR GOTO SetErrorOccured
     Result2=VAL(MID$(Result$,INSTR(Result$,",")+1))
     'If the string is not a valid number it's value will be 0
     ON ERROR GOTO 0 
 'RS-232 control ends
   CALL CkVxiErr(Address,"While sending query '"+Cmd$+"' to "+STR$(Address),1)	'If errs then stop
   IF 0<>ErrorOccured THEN
     CALL ReportErr("Expected two numbers, but received '"+Result$+"' while sending query '"+Cmd$+"' to "+STR$(Address)+" (using 0,0)")
     Result1=0
     Result2=0
   END IF
 END SUB 'GetVxi2NumberCk
 '
 SUB CharVxiFiles
 '
 '  This subprogram searches the disk and directory specified by SeDir$
 '  for files it recognizes as ROM programs or downloadable drivers.
 '  It fills in the number of drivers found and the list of driver
 '  names file sizes.
 '
   DIM DirList$			
   DIM PSuffix$,DSuffix$
 'RS-232 control begins
     PSuffix$="PC"
     DSuffix$="DC"
 'RS-232 control ends
   IF ""<>SeDir$ THEN
     CALL ReportStatus("Searching "+SeDir$+" for files ending in "+PSuffix$+" or "+DSuffix$)
   ELSE
     CALL ReportStatus("Searching current directory for files ending in "+PSuffix$+" or "+DSuffix$)
   END IF
   'There is no way to redirect the error messages, so a bad directory name
   'will print "Invalid Parameter" on the screen.  This program will give
   'an error when it attempts to open a file in that directory.
   SHELL "DIR "+SeDir$+" >"+DOSDirFile$
   OPEN DOSDirFile$ FOR INPUT AS #5
   PFFName$=""
   DFCount=1
   WHILE NOT EOF(5)
     LINE INPUT #5, DirList$
     DFFName$(DFCount)=LTRIM$(RTRIM$(MID$(DirList$,1,8-(1)+1)))+"."+LTRIM$(RTRIM$(MID$(DirList$,10,12-(10)+1)))
     LenFName=LEN(DFFName$(DFCount))
     IF 2<=LenFName THEN	'for files we use filename must be >=2 char
       IF DSuffix$=MID$(DFFName$(DFCount),LenFName-1) THEN
         DFCount=DFCount+1
       ELSE
         IF 5<=LenFName THEN	'for ROM program files filename must be >=5 char
           IF "1"+PSuffix$=MID$(DFFName$(DFCount),LenFName-3,LenFName-3-(LenFName-3)+1)+MID$(DFFName$(DFCount),LenFName-1) THEN
             IF ""<>PFFName$ THEN CALL Report("More than one ROM program file found, ignoring '"+PFFName$+"' and using '"+DFFName$(DFCount)+"'")
             PFFName$=DFFName$(DFCount)
           END IF
         END IF
       END IF
     END IF
   WEND
   CLOSE #5
   KILL DOSDirFile$
   DFCount=DFCount-1
   IF ""=PFFName$ THEN
     CALL ReportStatus("Found no ROM program file and "+STR$(DFCount)+" driver file(s)")
   ELSE
     CALL ReportStatus("Found ROM program file "+PFFName$+" and "+STR$(DFCount)+" driver file(s)")
   END IF
 END SUB 'CharVxiFiles
 '
 SUB GetPFInfo
 '
 ' This subprogram gets information about the ROM program file.
 '
   DIM JunkByte AS STRING * 1,CheckByte AS STRING * 1,LenByte AS STRING * 1
   DIM Expect$
 'RS-232 control begins
     ' Program file format:
     '   CONTENTS	               BYTES	MEANING
     '   -----------------		--      -------------------------------
     '   CNTL-D			 1	connect to display system (0x04)
     '   ST UNKNOWN\r		11	insure terminal control not used
     '   SI LOADER\r			10	connect to loader instrument
     '   *RST\r			 5	device reset
     '   PROG:DEL;		  	 9	SCPI command
     '   DEF:CHEC #8			11	SCPI command header
     '   dddddddd			 8 (BS)	size of data block, BS=2xROM
     '   ...				 N	flash ROM code, N=BS+(BS/80)
     '					this includes \r every 80 chars
     '   <CR>			 1	terminate command (0x0d)
     '
     Expect$=CHR$(04)+"ST UNKNOWN"+CHR$(13)+"SI LOADER"+CHR$(13)+"*RST"+CHR$(13)+"PROG:DEL;DEF:CHEC #8"
     CmdSize=LEN("PROG:DEL;DEF:CHEC #8")+8+1	'Cmd + 1 char fudge
 'RS-232 control ends
   '
   IF ""<>PFFName$ THEN
     BadFile=0	'FALSE
     ErrorOccured=0	'FALSE
     ON ERROR GOTO SetErrorOccured
     OPEN SeDir$+PFFName$ FOR BINARY AS #3
     GET #3,1,JunkByte$
     IF JunkByte$=CHR$(0) THEN ErrorOccured=1	'TRUE
     ON ERROR GOTO 0 
     IF 0<>ErrorOccured THEN
       CALL ReportErr("ROM program file '"+SeDir$+PFFName$+"' is empty or not readable (file will not be used)")
       BadFile=1	'TRUE
     ELSE
       BlkLenStart=LEN(Expect$)
       PFPSize=0
       FOR I=1 TO 8
         GET #3,BlkLenStart+I,LenByte$
         IF "0">LenByte$ OR "9"<LenByte$ THEN
           BadFile=1	'TRUE
         ELSE
           PFPSize=10*PFPSize+VAL(LenByte$)
         END IF
       NEXT I
       'Compute the size of all ROM program parts based on block size
 'RS-232 control begins
         PFFSize=BlkLenStart+8+PFPSize+((PFPSize+CmdSize+1) \ 79)+1
 'RS-232 control ends
       ' Check that the file looks okay
       FOR J=1 TO LEN(Expect$)
         GET #3,J,CheckByte$
         IF MID$(Expect$,J,J-(J)+1)<>CheckByte$ THEN BadFile=1	'TRUE
       NEXT J
       IF 0<>BadFile THEN CALL ReportErr("ROM program file '"+SeDir$+PFFName$+"' is not in proper format (file will not be used)")
     END IF
     CLOSE #3
     IF 0<>BadFile THEN PFFName$=""
   END IF
 END SUB 'GetPFInfo
 '
 SUB GetDFInfo
 '
 ' This subprogram gets information about the drivers whose names
 ' are in DFFName$.  If the file is not a driver it gives error + the file
 ' is removed from DFFName$.
 ' Otherwise the Driver revision number, Jump table revision number,
 ' downloaded size and file size are updated.
 '
   DIM JunkByte AS STRING * 1,CheckByte AS STRING * 1
   DIM Expect$(3)
   DIM Location(3)
 'RS-232 control begins
     ' Driver file format:
     '   CONTENTS	               BYTES	MEANING
     '   -----------------		--      -------------------------------
     '   CNTL-D			 1	connect to display system (0x04)
     '   ST UNKNOWN\r		11	insure terminal control not used
     '   SI SYSTEM\r			10	connect to system instrument
     '   *RST\r			 5	device reset
     '   DIAG:DRIV:LOAD:CHEC #8	22	SCPI command header
     '   dddddddd			 8 (BS)	size of data block, BS>2(DS+9)
     '   <0xFF><0x8E>		 2	driver start ID
     '   cx				 2	download format rev #(eg 0x80f1)
     '   cxcx			 4	required jump table rev #
     '   cxcxcxcx			 8 (DS)	DRAM memory required
     '   ...				 N	drive code, N=BS-18+(BS/80)
     '					this includes \r every 80 chars
     '   <0xFF><0xFF>		 2	driver end ID
     '   <CR>			 1	terminate command (0x0d)
     '
     DFFSizeMin=76			'DFFSize=1+11+10+5+22+8+BS+(BS/80)+1
     Expect$(1)=CHR$(04)+"ST UNKNOWN"+CHR$(13)+"SI SYSTEM"+CHR$(13)+"*RST"+CHR$(13)+"DIAG:DRIV:LOAD:CHEC #8"
     Expect$(2)=CHR$(255)+CHR$(142)		' = 0xFF8E
     Expect$(3)=CHR$(255)+CHR$(255)+CHR$(13)	' = 0xFFFF0d
 'RS-232 control ends
   '
   DFUseIdx=1
   FOR DFListIdx=1 to DFCount
     BadFile=0	'FALSE
     ErrorOccured=0	'FALSE
     ON ERROR GOTO SetErrorOccured
     OPEN SeDir$+DFFName$(DFListIdx) FOR BINARY AS #3
     GET #3,1,JunkByte$
     IF JunkByte$=CHR$(0) THEN ErrorOccured=1	'TRUE
     ON ERROR GOTO 0 
     IF 0<>ErrorOccured THEN
       CALL ReportErr("Driver file '"+SeDir$+DFFName$(DFListIdx)+"' is empty or not readable (file will not be used)")
       BadFile=1	'TRUE
     ELSE
       ' Find file size via binary search (LIF dir won't tell size exactly)
       DFFSizeTop=2^24
       DFFSizeBot=0
       WHILE (DFFSizeBot+1)<DFFSizeTop
         DFFSizeGuess=INT((DFFSizeTop+DFFSizeBot)/2)
         ErrorOccured=0	'FALSE
         GET #3,DFFSizeGuess,JunkByte$
         IF JunkByte$=CHR$(0) THEN ErrorOccured=1	'TRUE
         IF ErrorOccured THEN
           DFFSizeTop=DFFSizeGuess	'Guess was too big
         ELSE
           DFFSizeBot=DFFSizeGuess	'Guess was too small
         END IF
       WEND
       DFFSize(DFUseIdx)=DFFSizeBot	'DFFSize=INT((DFFSizeTop+DFFSizeBot)/2)
       BlkStart=LEN(Expect$(1))+8+1
       DFDJmpRev(DFUseIdx)=ReadWord(BinaryFile,BlkStart,2)
       DFDSizeHi=ReadWord(BinaryFile,BlkStart,4)
       DFDSizeLo=ReadWord(BinaryFile,BlkStart,6)
       DFDSize(DFUseIdx)=65536.0*DFDSizeHi+DFDSizeLo
       DFDSize(DFUseIdx)=4*INT((DFDSize(DFUseIdx)+3)/4)	'Long word alignment
       IF DFFSize(DFUseIdx)<DFFSizeMin THEN
         BadFile=1	'TRUE
       ELSE
         ' Check that the file looks okay
         Location(1)=1
         Location(2)=1+LEN(Expect$(1))+8
         Location(3)=DFFSize(DFUseIdx)-LEN(Expect$(3))+1
         FOR I=1 TO 3
           FOR J=1 TO LEN(Expect$(I))
             GET #3,Location(I)+J-1,CheckByte$
             IF MID$(Expect$(I),J,J-(J)+1)<>CheckByte$ THEN BadFile=1	'TRUE
           NEXT J
         NEXT I
       END IF
       IF 0<>BadFile THEN CALL ReportErr("Driver file '"+SeDir$+DFFName$(DFListIdx)+"' is not in proper format (file will not be used)")
     END IF
     CLOSE #3
     DFFName$(DFUseIdx)=DFFName$(DFListIdx)	'In case it's not bad
     IF 0=BadFile THEN DFUseIdx=DFUseIdx+1
   NEXT DFListIdx
   DFCount=DFUseIdx-1
 END SUB 'GetDFInfo
 '
 FUNCTION ReadWord(BinaryFile,BlkStart,BlkIdx)
 ' Reads a (possibly non-aligned) word from checked or unchecked blocks
   DIM TopNibble AS STRING * 1,LowNibble AS STRING * 1
 'RS-232 control begins
     ON ERROR GOTO SkipNextLine
     GET #3,BlkStart+BlkIdx*2,TopNibble$
     GET #3,BlkStart+BlkIdx*2+1,LowNibble$
     TopByte=16.0*(ASC(TopNibble$) MOD 16)+(ASC(LowNibble$) MOD 16)
     GET #3,BlkStart+BlkIdx*2+2,TopNibble$
     GET #3,BlkStart+BlkIdx*2+3,LowNibble$
     ON ERROR GOTO 0 
     LowByte=16.0*(ASC(TopNibble$) MOD 16)+(ASC(LowNibble$) MOD 16)
 'RS-232 control ends
   ReadWord=256.0*TopByte+LowByte : EXIT FUNCTION
 END FUNCTION 'ReadWord
 '
 SUB LoadFile(FileName$,TotalBytes,FirstCall)
   DIM Junk$
   DIM NextByte AS STRING * 1
   DIM Direct$
   IF FirstCall THEN
     BytesSent=0
     ErrorOccured=0
     ON ERROR GOTO SetErrorOccured
     OPEN FileName$ FOR BINARY AS #3
     ON ERROR GOTO 0
     IF ErrorOccured THEN CALL ReportErrStop("Could not open file "+FileName$)
     CALL Report("Total byte size for download: "+STR$(TotalBytes)+" bytes")
   ELSE   'used for ROM Program downloading of parts 2 and above
     DO
       ErrorOccured=0
       ON ERROR GOTO SetErrorOccured
       SHELL "DIR "+SeDir$+" >"+DOSDirFile$
       OPEN DOSDirFile$ FOR INPUT AS #5
       ON ERROR GOTO 0
       IF ErrorOccured THEN CALL ReportErrStop("Could not search directory for "+FileName$)
       NotFound=1
       WHILE NOT EOF(5)
          LINE INPUT #5, Direct$
          IF INSTR(Direct$,MID$(FileName$,1,LEN(FileName$)-3-(1)+1)) THEN NotFound=0
       WEND
       CLOSE #5
       KILL DOSDirFile$
       IF NotFound THEN
          Ver$=MID$(FileName$,LEN(FileName$)-3,1)
          CALL ReportStatus("Insert DOS diskette #"+Ver$+".  Press any key to continue.")
          DO 
          LOOP UNTIL INKEY$<>""
          ErrorOccured=1
          CALL ReportStatus("")
       END IF
     LOOP UNTIL ErrorOccured=0  
     ON ERROR GOTO SetErrorOccured
     OPEN FileName$ FOR BINARY AS #3
     ON ERROR GOTO 0
     IF ErrorOccured THEN CALL ReportErrStop("Could not open file "+FileName$)
   END IF
   CALL Report("Downloading '"+FileName$+"'")
 'RS-232 control begins
     IF 0<>FirstCall THEN
       CALL SendVxiCk(SysAddr,"*OPC")	'Make sure instr. is selectable
       RespEndCnt=0	'The first RespEnds are treated specially
     ELSE
       RespEndCnt=2	'At least 2 RespEnds have been sent already
     END IF
     DO
       ErrorOccured=0	'FALSE
       GET #3,,NextByte$
       IF NextByte$=CHR$(0) THEN ErrorOccured=1	'TRUE
       IF ErrorOccured THEN
         IF LastError<>EOFError THEN CALL ReportErrStop("trouble reading "+FileName$)
       ELSE
         ErrorOccured=0	'FALSE
         ON ERROR GOTO SetErrorOccured
         PRINT #1,NextByte$;
         ON ERROR GOTO 0 
         IF 0<>ErrorOccured THEN CALL IOTimeOutStop
         BytesSent=BytesSent+1
         IF CHR$(13)=NextByte$ THEN
           IF 2<=RespEndCnt THEN
             CALL GetVxiPattern(AnyString$+ResponseEnd$,Junk$)
           ELSE	'First two \r in file create multiple \r's returned
             IF 1=RespEndCnt THEN	'^Dst unknown\n -> Select...\nst...own\nSelect..\n...OWN\n
               CALL GetVxiPattern(AnyString$+ResponseEnd$+AnyString$+ResponseEnd$+AnyString$+ResponseEnd$+AnyString$+ResponseEnd$,Junk$)
             ELSE	'si system\n -> si system\n..._0: busy\n..._0:\n
               CALL GetVxiPattern(AnyString$+ResponseEnd$+AnyString$+ResponseEnd$+AnyString$+ResponseEnd$,Junk$)
             END IF
             RespEndCnt=RespEndCnt+1
           END IF
           CALL ReportStatus(STR$(BytesSent))
         END IF
       END IF
     LOOP UNTIL ErrorOccured AND LastError=EOFError
 'RS-232 control ends
   CLOSE #3
 END SUB 'LoadFile
 '
 SUB CleanUp
   ON ERROR GOTO SkipNextLine
   IF ""<>SeLog$ THEN
     CLOSE #4
   END IF
   KILL DOSDirFile$
   ON ERROR GOTO 0
 'RS-232 control begins
     ON ERROR GOTO SkipNextLine
     PRINT #1,CHR$(4)	'disconnect from the instruments
     ON ERROR GOTO 0
 'RS-232 control ends
 END SUB 'CleanUp
 '
 SUB ExecuteCmds(BatchFileName$,Label$)	'Do commands in config file
 ' This subprogram executes any line in the configuration file
 ' that is in the proper format:
 '   Label=<number>,<string to be sent>
 ' The leading number must be between 0 and 30 and is the secondary
 ' address of the instrument for which the command is intended.  If
 ' the command is sent via RS-232 we will use a LADD of 8*secondary address.
 ' If command sent generates an error, we stop and display the error.
   CALL ReportStatus("Sending '"+Label$+"' commands from '"+BatchFileName$+"' file")
   DIM Cmds$(80)	 'CmdCountMax, BatchLineLenMax
   'Get list of commands
   CALL GetBatchStrRep(BatchFileName$,Label$,Cmds$(),CmdCount)
   FOR I=1 TO CmdCount
     ErrorOccured=0	'FALSE
     Addr=VAL(Cmds$(I))
     'If the string is not a valid number it's value will be 0
     IF ""=LTRIM$(RTRIM$(Cmds$(I))) THEN ErrorOccured=1
     IF 0<>ErrorOccured THEN
       CALL ReportErr(BatchFileName$+" contains a value for '"+Label$+"' which should start with a numeric address, '"+Cmds$(I)+"' will not be used")
     ELSE
       IF Addr<0 OR Addr>30 THEN 
         CALL ReportErr(BatchFileName$+" contains a value for '"+Label$+"' which should start with an address (0-30), '"+Cmds$(I)+"' will not be used")
       ELSE
 'RS-232 control begins
           Addr=8*Addr	'Change to LADD
 'RS-232 control ends
         IF 0=INSTR(Cmds$(I),",") THEN
           CALL ReportErr(BatchFileName$+" contains a value for '"+Label$+"' which is missing the ',' after the address, '"+Cmds$(I)+"' will not be used")
         ELSE
           Cmds$(I)=MID$(Cmds$(I),INSTR(Cmds$(I),",")+1)
           CALL Report("Sending '"+Cmds$(I)+"' to "+STR$(Addr))
           IF 0<>INSTR(UCASE$(Cmds$(I)),"DIAG:BOOT") THEN  'If command is DIAG:BOOT
             CALL SendVxi(Addr,Cmds$(I))
             SLEEP 2			'Make sure re-boot has a chance to start
 'RS-232 control begins
               CALL DumpVxiInput
 'RS-232 control ends
             CALL FinishReboot
           ELSE
             CALL SendVxiCk(Addr,Cmds$(I))
           END IF
         END IF
       END IF
     END IF
   NEXT I
 END SUB 'ExecuteCmds
